#include <string.h>
#include <stdlib.h>
#include <rtthread.h>
#include <finsh.h>
#include <dfs_posix.h>
#include "wav.h"

/* Header Table containing the audio file information */
rt_uint32_t HeaderTabIndex = 0;
rt_uint8_t * AudioFileHeader;

/*******************************************************************************
* Function Name  : ReadUnit
* Description    : Reads a number of bytes from the SPI Flash and reorder them
*                  in Big or little endian.
* Input          : - NbrOfBytes : number of bytes to read.
*                    This parameter must be a number between 1 and 4.
*                  - ReadAddr : external memory address to read from.
*                  - Endians : specifies the bytes endianness.
*                    This parameter can be one of the following values:
*                          - LittleEndian
*                          - BigEndian
* Output         : None
* Return         : Bytes read from the SPI Flash.
*******************************************************************************/
static rt_uint32_t ReadUnit(rt_uint8_t NbrOfBytes, Endianness BytesFormat)
{
  rt_uint32_t index = 0;
  rt_uint32_t Temp = 0;

  if(BytesFormat == LittleEndian)
  {
    for(index = 0; index < NbrOfBytes; index++)
    {
      Temp |= AudioFileHeader[HeaderTabIndex++] << (index * 8);
    }
  }
  else
  {
    for(index = NbrOfBytes; index != 0; index--)
    {
      Temp |= AudioFileHeader[HeaderTabIndex++] << ((index-1) * 8);
    }
  }

  return Temp;
}

/*******************************************************************************
* Function Name  : I2S_CODEC_WaveParsing
* Description    : Checks the format of the .WAV file and gets information about
*                  the audio format. This is done by reading the value of a
*                  number of parameters stored in the file header and comparing
*                  these to the values expected authenticates the format of a
*                  standard .WAV  file (44 bytes will be read). If  it is a valid
*                  .WAV file format, it continues reading the header to determine
*                  the  audio format such as the sample rate and the sampled data
*                  size. If the audio format is supported by this application,
*                  it retrieves the audio format in WAVE_Format structure and
*                  returns a zero value. Otherwise the function fails and the
*                  return value is nonzero.In this case, the return value specifies
*                  the cause of  the function fails. The error codes that can be
*                  returned by this function are declared in the header file.
* Input          : None
* Output         : None
* Return         : Zero value if the function succeed, otherwise it return
*                  a nonzero value which specifies the error code.
*******************************************************************************/
ErrorCode I2S_CODEC_WaveParsing(rt_uint8_t* HeaderTab, WAVE_FormatTypeDef  *WAVE_Format)
{
	rt_uint32_t Temp = 0x00;
	rt_uint32_t ExtraFormatBytes = 0;
	
	AudioFileHeader = HeaderTab;
	/* Initialize the HeaderTabIndex variable */
	HeaderTabIndex = 0;

	/* Read chunkID, must be 'RIFF'	----------------------------------------------*/
	Temp = ReadUnit(4, BigEndian);
	if(Temp != ChunkID)
	{
		return(Unvalid_RIFF_ID);
	}
	/* Read the file length ----------------------------------------------------*/
	WAVE_Format->RIFFchunksize = ReadUnit(4, LittleEndian);
	
	/* Read the file format, must be 'WAVE' ------------------------------------*/
	Temp = ReadUnit(4, BigEndian);
	if(Temp != FileFormat)
	{
		return(Unvalid_WAVE_Format);
	}
	/* Read the format chunk, must be 'fmt ' -----------------------------------*/
	Temp = ReadUnit(4, BigEndian);
	if(Temp != FormatID)
	{
		return(Unvalid_FormatChunk_ID);
	}
	/* Read the length of the 'fmt' data, must be 0x10 -------------------------*/
	Temp = ReadUnit(4, LittleEndian);
	if(Temp != 0x10)
	{
		ExtraFormatBytes = 1;
	}
	/* Read the audio format, must be 0x01 (PCM) -------------------------------*/
	WAVE_Format->FormatTag = (rt_uint16_t)ReadUnit(2, LittleEndian);
	if(WAVE_Format->FormatTag != WAVE_FORMAT_PCM)
	{
		return(Unsupporetd_FormatTag);	
	}
	/* Read the number of channels: 0x02->Stereo 0x01->Mono --------------------*/
	WAVE_Format->NumChannels = (rt_uint16_t)ReadUnit(2, LittleEndian);

	/* Read the Sample Rate ----------------------------------------------------*/
	WAVE_Format->SampleRate = ReadUnit(4, LittleEndian);

	/* Read the Byte Rate ------------------------------------------------------*/
	WAVE_Format->ByteRate = ReadUnit(4, LittleEndian);
	
	/* Read the block alignment ------------------------------------------------*/
	WAVE_Format->BlockAlign = (rt_uint16_t)ReadUnit(2, LittleEndian);
	
	/* Read the number of bits per sample --------------------------------------*/
	WAVE_Format->BitsPerSample = (rt_uint16_t)ReadUnit(2, LittleEndian);
	if(WAVE_Format->BitsPerSample != Bits_Per_Sample_16)
	{
		return(Unsupporetd_Bits_Per_Sample);
	}
	/* If there are Extra format bytes, these bytes will be defined in "Fact Chunk" */
	if(ExtraFormatBytes == 1)
	{
		/* Read th Extra format bytes, must be 0x00 ------------------------------*/
		Temp = ReadUnit(2, LittleEndian);
		if(Temp != 0x00)
		{
			return(Unsupporetd_ExtraFormatBytes);
		}
		/* Read the Fact chunk, must be 'fact' -----------------------------------*/
		Temp = ReadUnit(4, BigEndian);
		if(Temp != FactID)
		{
			return(Unvalid_FactChunk_ID);
		}
		/* Read Fact chunk data Size ---------------------------------------------*/
		Temp = ReadUnit(4, LittleEndian);

		/* Set the index to start reading just after the header end */
		HeaderTabIndex += Temp;
	}
	/* Read the Data chunk, must be 'data' -------------------------------------*/
	Temp = ReadUnit(4, BigEndian);
	if(Temp != DataID)
	{
		return(Unvalid_DataChunk_ID);
	}
	/* Read the number of sample data ------------------------------------------*/
	WAVE_Format->DataSize = ReadUnit(4, LittleEndian);
  
	return(Valid_WAVE_File);	
}


